<?php
// +----------------------------------------------------------------------
// | Bwsaas
// +----------------------------------------------------------------------
// | Copyright (c) 2015~2020 http://www.buwangyun.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Gitee ( https://gitee.com/buwangyun/bwsaas )
// +----------------------------------------------------------------------
// | Author: buwangyun <hnlg666@163.com>
// +----------------------------------------------------------------------
// | Date: 2020-9-28 10:55:00
// +----------------------------------------------------------------------

namespace app\common\model;

use buwang\base\BaseModel;
use buwang\traits\JwtTrait;
use buwang\util\Util;

/**
 * 租户操作类
 * Class User
 * @package app\common\model
 */
class User extends BaseModel
{
    use JwtTrait;


    /**头像获取器
     * @param $value
     * @return mixed
     */
    public function getAvatarAttr($value)
    {
        return bw_img_url($value?:'/static/manage/images/default_user_head.png',request()->domain());//TODO 2021/5/20 用户无头像增加默认头像
    }


    /**
     * 判断invite_code用户是否存在
     * @param $invite_code
     * @param null $member_miniapp_id
     * @return int|mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function isInvite($invite_code, $member_miniapp_id = null)
    {
        if (empty($invite_code)) {
            return 0;
        }
        $id = de_code(strtoupper($invite_code));
        $self = new self;
        if ($member_miniapp_id) $self = $self->where('member_miniapp_id', $member_miniapp_id);
        $is_invite = $self->where(['id' => $id])->field('id')->find();
        return empty($is_invite) ? 0 : $is_invite['id'];
    }

    public static function checkPassword($password, $safePassword)
    {
        //验证安全密码
        if (password_verify(md5($password), $safePassword)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证用戶信息
     * @param $username
     * @param $password
     * @param null $member_miniapp_id
     * @return array|bool|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function validateUser($username, $password, $member_miniapp_id = null)
    {
        //判断用户是否存在
        $self = self::where('username|mobile', $username);
        if ($member_miniapp_id) $self = $self->where('member_miniapp_id', $member_miniapp_id);
        $userInfo = $self->find();
        if (!$userInfo) return self::setError('用户名或密码错误');
        if ($userInfo['status'] == 0) return self::setError('用户信息获取失败');
        //得到加密后的密码
        if (!self::checkPassword($password, $userInfo['password'])) return self::setError('用户名或密码错误');
        return $userInfo;
    }

    /**
     * 登录用戶User
     * @param $user
     * @param $scopes
     * @param bool $trans
     * @return array|bool
     */
    public static function loginUser($user, $scopes, $trans = false)
    {
        if (!in_array($scopes, BW_CLIENT_TYPE)) return self::setError('scopes类型错误');
        if ($trans) {
            self::beginTrans();
        }
        $res = $res1 = $res2 = $tokenInfo = true;
        try {
            $data = [
                'id' => $user['id'],
                'nickname' => $user['nickname'] ?: '',
                'mobile ' => $user['mobile'] ?: '',
            ];
            //执行生成token,并把数据保存到session和redis中
            $tokenInfo = self::getAccessToken($data, $scopes);
            //存儲token相关信息
            // $res2 = Token::updateToken($user['id'], $tokenInfo['token'], 'admin');
            //更新用户登录信息
            $user->login_time = time();
            $user->login_ip = request()->ip();
            $res1 = $user->save();

            $res = $res1 && $res2 && $tokenInfo && true;
            if ($trans) {
                self::checkTrans($res);
            }
            // 用户登录成功后事件
            event('UserLoginSuccess', [$user, $scopes]);
        } catch (\Exception $e) {
            if ($trans) {
                self::rollbackTrans();
            }
            return self::setError($e->getMessage());
        }
        if (!$tokenInfo) return self::setError('获取AccessToken或存储失败');
        if (!$res1) return self::setError('更新用户登录信息失败');
        if (!$res2) return self::setError('更新用户验证信息失败');
        return $tokenInfo;
    }

    /**
     * 通过微信注册或更新
     * @param array $wechat
     * @param string $type mini_program小程序  official公众号
     * @param false $trans
     * @return bool|int|mixed|string
     */
    public static function wechatReg(array $wechat, $type = 'mini_program', $trans = false)
    {
        //参数
        $data = [];
        $updata = [];
        $data['member_miniapp_id'] = $wechat['miniapp_id'];//MemberMiniapp表id
        $data['nickname'] = $wechat['nickname'];//昵称
        $data['avatar'] = $wechat['avatar']; //头像
        $data['unionid'] = $wechat['unionid'];//unionid
        $data['login_time'] = time(); //登陆时间
        $data['update_time'] = time(); //更新时间
        $data['login_ip'] = request()->ip();  //登录ip
        if ($type == 'mini_program') {//小程序
            $data['session_key'] = $wechat['session_key']; //小程序session_key
            $data['miniapp_uid'] = $wechat['miniapp_uid']; //小程序用户id
        } elseif ($type == 'official') {//公众号
            $data['official_uid'] = $wechat['official_uid'];//公众号openid
        } else {
            //app
            $data['username'] = $wechat['username'];
            $data['password'] = $wechat['password'];
        }
        $condition['member_miniapp_id'] = $wechat['miniapp_id']; //区分哪个应用
        //小程序和公众号
        if($type !='app'){
            $userModel = self::getBaseWhere($data);
            $info = $userModel->findOrEmpty();
            //如果没传手机号又查不到注册的账号或账号里也没手机号
            if(!$wechat['mobile']){
                if(!$info)return self::setError('请提交手机号', 400832);
                if(!$info['mobile'])return self::setError('请提交手机号', 400832);
                //账号里有手机号
                $wechat['mobile'] = $info['mobile'];
            }
        }

        /**
         * 先查手机号是否存在
        如果手机号不存在
        {
        账号存在   ，更新手机号
        账号不存在，创建新账号
        }
        如果手机号存在 ，只做更新操作
        {
        对应的id存在   ，不合法，退出流程
        对应的id不存在，合法   ，更新操作
        }
         */
        $mobileUser = $userModel = self::where($condition)->where('mobile',$wechat['mobile'])->findOrEmpty();
        // 如果手机号存在,只做更新操作
        if(!$mobileUser->isEmpty()){
            //如果被封禁则不让登录
            if(!$mobileUser['status']||$mobileUser['is_delete'])return self::setError('用户信息获取失败');
            if ($type == 'mini_program') {  //小程序
                //账号存在并且不是自己
                if($mobileUser['miniapp_uid']&&$mobileUser['miniapp_uid']!=$wechat['miniapp_uid'])return self::setError('手机号已被绑定，请使用其他手机号', 400832);

            } elseif ($type == 'official') { //公众号
                //账号存在并且不是自己
                if($mobileUser['official_uid']&&$mobileUser['official_uid']!=$wechat['official_uid'])return self::setError('手机号已被绑定，请使用其他手机号', 400832);
            }
            $info = $mobileUser;
        }
        if ($trans) self::startTrans();
        $res = true;
        try {
            if ($info->isEmpty()) {//新注册用户
                $data['mobile'] = $wechat['mobile'];
                $is_insert = true;
                //用户在小程序应用设置里面进行公众号绑定操作
                if ($type == 'mini_program' && !empty($wechat['official_uid'])) {
                    if(!empty($wechat['official_uid'])){
                        //绑定公众号需满足该公众号未被自己绑定并没有被其他人使用
                        $official_info = self::where('member_miniapp_id',$wechat['miniapp_id'])->where('official_uid',$wechat['official_uid'])->find();
                        if($official_info)return self::setError('公众号已被其他用户绑定，请联系客服咨询');
                        $data['official_uid'] = $wechat['official_uid'];
                    }
                }
                //判断是否需要插入数据
                if ($is_insert) {
                    $data['create_time'] = time();
                    $is_invite = $wechat['invite_code'] ? self::isInvite($wechat['invite_code'], $wechat['miniapp_id']) : false;  //查邀请码是否有效
                    if ($is_invite) {
                        $data['pid'] = de_code($wechat['invite_code']);//注册用户加入上级推荐人
                    }
                    $last_id = self::insertGetId($data);
                    if ($last_id) {
                        self::where('id', $last_id)->data(['invite_code' => en_code($last_id)])->update();//每个人的邀请码是根据ID生成的可解密code
                        /**-------------20200910 jyk 注册成功后创建对应应用的用户副表 start-----------------**/
                        $user = self::find($last_id);
                        //用户注册成功后事件
                        event('UserRegisterSuccess', [$user, $type]);
                        /**-------------20200910 jyk 注册成功后创建对应应用的用户副表 end-----------------**/
                    }
                }
            } else { //老用户更新
                $updata['mobile'] = $wechat['mobile'];
                $updata['nickname'] = $wechat['nickname'];
                $updata['avatar'] = $wechat['avatar'];
                $updata['login_time'] = time();
                $updata['login_ip'] = request()->ip();
                $updata['unionid'] = $wechat['unionid'];//unionid
                if ($type == 'mini_program') {
                    $updata['session_key'] = $wechat['session_key'];
                    $updata['miniapp_uid'] = $wechat['miniapp_uid'];
                    if(!empty($wechat['official_uid'])){
                        //绑定公众号需满足该公众号未被自己绑定并没有被其他人使用
                        $official_info = self::where('member_miniapp_id',$wechat['miniapp_id'])->where('official_uid',$wechat['official_uid'])->find();
                        if($official_info&&$official_info['id']!=$info['id'])return self::setError('公众号已被其他用户绑定，请联系客服咨询');
                        $updata['official_uid'] = $wechat['official_uid'];
                    }

                }
                if ($type == 'official') $updata['official_uid'] = $wechat['official_uid'];
                $is_invite = $wechat['invite_code'] ? self::isInvite($wechat['invite_code'], $wechat['miniapp_id']) : false;  //查邀请码是否有效
                if ($is_invite) {
                    if (!$info['pid']){
                        $updata['pid'] = de_code($wechat['invite_code']);//注册用户加入上级推荐人
                        $bindable = self::bindable($info['id'], $updata['pid']);
                        if(!$bindable)return self::setError('不能绑定自己的下级用户');
                    }
                }

                self::where(['id' => $info['id']])->data($updata)->update();
                $last_id=  $info->id;
                $user = self::find($info->id);
                //用户更新成功后事件
                event('UserUpdateSuccess', [$user, $type]);
            }

            $res = $res && true;
            if ($trans) {
                self::checkTrans($res);
            }
        } catch (\Exception $e) {
            if ($trans) {
                self::rollback();
            }
            return self::setError("用户信息插入或更新失败".$e->getMessage());
        }
        if (!$res) return self::setError('用户信息插入或更新失败');

        return $last_id;
    }

    /**
     * 字节跳动旗下应用用户注册或更新
     * @param array $byte_dance_data
     * @param string $type tt 头条小程序  dy 抖音小程序 xg 西瓜小程序
     * @param false $trans
     * @return bool|int|mixed|string
     */
    public static function byteDanceReg(array $byte_dance_data, $type = 'tt', $trans = false)
    {
        //参数
        $data = [];
        $updata = [];
        $data['member_miniapp_id'] = $byte_dance_data['member_miniapp_id'];//MemberMiniapp表id
        $data['tt_nickname'] = $byte_dance_data['nickName'];//昵称
        $data['tt_avatar'] = $byte_dance_data['avatarUrl']; //头像
        $data['tt_unionid'] = $byte_dance_data['unionid'];//unionid
        $data['login_time'] = time(); //登陆时间
        $data['update_time'] = time(); //更新时间
        $data['login_ip'] = request()->ip();  //登录ip
        switch ($type){
            case $type == 'tt':
                $data['tt_session_key'] = $byte_dance_data['session_key']; //小程序session_key
                $data['tt_uid'] = $byte_dance_data['openid']; //小程序用户id
            default:
                //
        }
        $condition['member_miniapp_id'] = $byte_dance_data['member_miniapp_id']; //区分哪个应用
        $userModel = self::getBaseWhere($data);
        $info = $userModel->findOrEmpty();
        //如果没传手机号又查不到注册的账号或账号里也没手机号
        if(!$byte_dance_data['mobile']){
            if(!$info || !$info['mobile']) return self::setError('请提交手机号', 400832);
            //账号里有手机号
            $byte_dance_data['mobile'] = $info['mobile'];
        }

        /**
         * 先查手机号是否存在
        如果手机号不存在
        {
        账号存在   ，更新手机号
        账号不存在，创建新账号
        }
        如果手机号存在 ，只做更新操作
        {
        对应的id存在   ，不合法，退出流程
        对应的id不存在，合法   ，更新操作
        }
         */
        $mobileUser = $userModel = self::where($condition)->where('mobile',$byte_dance_data['mobile'])->findOrEmpty();
        // 如果手机号存在,只做更新操作
        if(!$mobileUser->isEmpty()){
            //如果被封禁则不让登录
            if(!$mobileUser['status']||$mobileUser['is_delete']) return self::setError('用户信息获取失败');
            switch ($type){
                case $type == 'tt':
                    if($mobileUser['tt_uid'] && $mobileUser['tt_uid'] != $data['tt_uid']) return self::setError('手机号已被绑定，请使用其他手机号', 400832);
                default:
                    //
            }
            $info = $mobileUser;
        }
        if ($trans) self::startTrans();
        $res = true;
        try {
            if ($info->isEmpty()) {//新注册用户
                $data['mobile'] = $byte_dance_data['mobile'];
                //需要插入数据
                $data['create_time'] = time();
                $is_invite = $byte_dance_data['invite_code'] ? self::isInvite($byte_dance_data['invite_code'], $byte_dance_data['member_miniapp_id']) : false;  //查邀请码是否有效
                if ($is_invite) $data['pid'] = de_code($byte_dance_data['invite_code']);//注册用户加入上级推荐人
                //插入用户数据
                $last_id = self::insertGetId($data);
                if ($last_id) {
                    self::where('id', $last_id)->data(['invite_code' => en_code($last_id)])->update();//每个人的邀请码是根据ID生成的可解密code
                    $user = self::find($last_id);
                    //用户注册成功后事件
                    event('UserRegisterSuccess', [$user, $type]);
                }
            } else { //老用户更新
                $updata['mobile'] = $byte_dance_data['mobile'];
                $updata['tt_nickname'] = $byte_dance_data['nickName'];
                $updata['tt_avatar'] = $byte_dance_data['avatarUrl'];
                $updata['login_time'] = time();
                $updata['login_ip'] = request()->ip();
                $updata['tt_unionid'] = $byte_dance_data['unionid'];//unionid
                if ($type == 'tt') {
                    $updata['tt_session_key'] = $byte_dance_data['session_key'];
                    $updata['tt_uid'] = $byte_dance_data['openid'];
                }
                $is_invite = $byte_dance_data['invite_code'] ? self::isInvite($byte_dance_data['invite_code'], $byte_dance_data['member_miniapp_id']) : false;  //查邀请码是否有效
                if ($is_invite) {
                    if (!$info['pid']) {
                        $updata['pid'] = de_code($byte_dance_data['invite_code']);//如果不存在，就加入上级推荐人
                        $bindable = self::bindable($info['id'], $updata['pid']);
                        if(!$bindable)return self::setError('不能绑定自己的下级用户');
                    }
                }

                self::where(['id' => $info['id']])->data($updata)->update();
                $last_id=  $info->id;
                $user = self::find($info->id);
                //用户更新成功后事件
                event('UserUpdateSuccess', [$user, $type]);
            }

            $res = $res && true;
            if ($trans) {
                self::checkTrans($res);
            }
        } catch (\Exception $e) {
            if ($trans) {
                self::rollback();
            }
            return self::setError("用户信息插入或更新失败：".$e->getMessage());
        }
        if (!$res) return self::setError('用户信息插入或更新失败');
        return $last_id;
    }


    /**
     * 更新安全密码
     * @param int $uid
     * @param string $safe_password
     * @return User
     */
    public static function updateSafePasspord(int $uid, string $safe_password)
    {
        $data['safe_password'] = password_hash(md5($safe_password), PASSWORD_DEFAULT);
        return self::where(['id' => $uid])->update($data);
    }

    /**
     * 修改登录密码
     * @access public
     */
    public function upLoginPasspowrd(int $uid, string $password)
    {
        $data['password'] = password_hash(md5($password), PASSWORD_DEFAULT);
        return self::where(['id' => $uid])->update($data);
    }

    /**
     * 锁定用户
     * @param int $appid
     * @param int $id
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function lockUser(int $appid, int $id)
    {
        $result = self::where(['member_miniapp_id' => $appid, 'id' => $id])->find();
        if ($result->is_delete >= 1) {
            return FALSE;
        }
        $result->status = $result->status ? 0 : 1;
        return $result->save();
    }

    /**
     * 登录用户ID
     * @param array $data
     * @param int $id
     * @return User
     */
    public static function edit(array $data, int $id)
    {
        return User::where(['id' => $id])->update($data);
    }

    /**
     * 得到账号基础查询条件
     * @param array $whereData
     * @param null $model
     * @param string $alisa
     * @return User
     */
    public static function getBaseWhere($whereData=[],$model=null,$alisa = ''){
        if(!$model){
            $model = new self;
            if($alisa)$model = $model->alias($alisa);
        }
        if($alisa)$alisa = $alisa.'.';
        $model = $model->where("{$alisa}unionid <> '' OR {$alisa}official_uid <> '' OR {$alisa}miniapp_uid <> '' OR {$alisa}tt_unionid <> '' OR {$alisa}tt_uid <> '' OR {$alisa}mobile <> ''");
        isset($whereData['official_uid']) && $whereData['official_uid'] && $model = $model->where("{$alisa}official_uid", $whereData['official_uid']);
        isset($whereData['miniapp_uid']) && $whereData['miniapp_uid'] && $model = $model->where("{$alisa}miniapp_uid", $whereData['miniapp_uid']);
        isset($whereData['tt_uid']) && $whereData['tt_uid'] && $model = $model->where("{$alisa}tt_uid", $whereData['tt_uid']);
        isset($whereData['member_miniapp_id']) && $whereData['member_miniapp_id'] && $model = $model->where("{$alisa}member_miniapp_id", $whereData['member_miniapp_id']);
        return $model;
    }

    /**搜素该用户团队所有成员
     */
    public static function userList($uid = 0, $user_list = [])
    {
        $uids = [];
        //查询所有用户树
        if (!$user_list) {
            $user = self::where('id', $uid)->find();
            if (!$user) return compact('user_list', 'uids');
            $user_list = self::where('member_miniapp_id', $user['member_miniapp_id'])->column('nickname,avatar,mobile,id,pid', 'id');
        }
        if (!$user_list) return compact('user_list', 'uids');
        $user_list = Util::tree($user_list, 'id', 'pid', 'child', $uid);
        //关系树下的所有用户id
        $uids = Util::getTreeItem($user_list, 'id');
        return compact('user_list', 'uids');
    }

    /**判断是否允许绑定
     */
    public static function bindable($uid, $pid)
    {
        $data = self::userList($uid);
        return in_array($pid, $data['uids']) ? false:true;
    }

}